package analyticsServer;

import java.rmi.RemoteException;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import managementClient.IClientRMI;

/**
 * Collection Class for Subscriptions.
 * Contains out of 2 hashmaps, one with subscription-id as key and callback-Object+regex as values (encapsulated in CallRex-Object).
 * And one with callback-Object as key and subscription-id+regex as values (encapsulated in SubRex-Object).
 * 
 * Needed, access with id (unsubscribe)and callback (send, connection lost),
 * send needs all regexes of client
 * @author Group 95
 */
public class SubscriptionCollection 
{
    private static int uniqueId=0;
    
    private CopyOnWriteArrayList<AnalyticsClient> arClients;
    
    public SubscriptionCollection()
    {
        this.arClients=new CopyOnWriteArrayList<AnalyticsClient>();
    }
    
    private int getIndexOfClientId(String clientId)
    {
        synchronized(this)
        {
            for(int i=0;i<arClients.size();i++)
            {
                if(arClients.get(i).getId().equals(clientId))
                    return i;
            }
        }
        return -1;
    }
    
    /**
     * Adds a new Subscription.
     * Will be added to both hashmap
     * @param client who subscribes
     * @param regex used by Analyticsserver to filter the Events
     * @return unique Subscription-Id
     */
    public String add(IClientRMI client,String regex) throws RemoteException
    {
        String clientId=client.getId();
        String subId=Integer.toString(uniqueId++);
        synchronized(this)
        {
            int clientIndex=getIndexOfClientId(clientId);
            if(clientIndex<0)
            {
                arClients.add(new AnalyticsClient(client,clientId, subId, regex));
            }
            else
            {
                arClients.get(clientIndex).addSubscription(subId, regex);
            }
        }
        return clientId+subId;
    }

    
    /**
     * Removes a Subscription.
     * Will be Removed from hashmaps
     * @param id UUID of Client (36 signs)
     * returns true if subscription was removed, false if it was not found
     */    
    public boolean removeSubscription(String id)
    {
        boolean bRet=false;
        String clientId=id.substring(0, 36);//36=length of UUID=ID of Client, afterwards comes the subscription identifier
        synchronized(this) //index could change between get and delete
        {
            int clientIndex=getIndexOfClientId(clientId);
            if(clientIndex>=0)
            {
                AnalyticsClient client=arClients.get(clientIndex);
                bRet = client.deleteSubscription(id.substring(36));
                if(client.hasNoSubscriptions())
                {
                    arClients.remove(clientIndex);
                }
            }
        }
        return bRet;
    }
    
    /**
     * Removes a Client and all of his Subscriptions.
     * Will be Removed from hashmaps
     * @param id UUID of Client
     * returns true if subscription was removed, false if it was not found
     */    
    public synchronized boolean remove(String clientId) 
    {
        return arClients.remove(this.getIndexOfClientId(clientId))!=null;
    }
    
    
    /**
     * Returns all Clients of the SubscriptionCollection.
     * @return AnaLyticsClient[] clients
     */
    public synchronized Iterator<AnalyticsClient> iterator()
    {
        return this.arClients.iterator();
    }
}
